<?php

/**
 * ORM Class
 *
 *  @version 1.0
 *  @package Nucleo
 *  @subpackage Nucleo.Model
 *  @copyright 2009-2010 Renan Abreu
 *
 *  @author Renan Henrique Abreu <renanhabreu@gmail.com>
 */
class Nucleo_Model_Object implements Nucleo_Model_Mapper {
    protected $tb = null;
    protected $pk = null; // Array
    protected $fk = null; // Array('table_fk'=>'col_fk')
    protected $cols = null; // Array('col_name')
    protected $varUpper = true;
    public   $children = Array();
    private   $colsValues = Array();
    static private $instanceId = Array();


    private function  __construct($parameter) {
        if(isset($parameter)) {
            $this->tb       = $parameter['tb'];
            $this->pk       = $parameter['pk'];
            $this->fk       = $parameter['fk'];
            $this->cols     = $parameter['cols'];
            $this->varUpper = $parameter['varUpper'];
        }

        Nucleo_Model_Model::getConnection();
    }

    static protected function createMapper($parameter = NULL,$id = NULL) {
        $instance = NULL;
        if(!isset($id)) {
            $instance = new self($parameter);
        }else {
            if(!isset(self::$instanceId[$parameter['tb']][$id]))
                self::$instanceId[$parameter['tb']][$id] = new self($parameter);

            $instance = self::$instanceId[$parameter['tb']][$id];
        }
        return $instance;
    }

    /**
     * Maker of the SQL INSERT query
     * @return boolean
     */
    public function save() {

        $parameter = Array();
        $parameterExec = NULL;
        foreach($this->cols as $value=>$type) {
            if(isset($this->colsValues[$value])) {
                $parameter[$value] = '?';
                $parameterExec[] = $this->colsValues[$value];
            }
        }
        if(isset(self::$instanceId[$this->tb][$this->colsValues[$this->pk]])) {
            $expUpdate = '';
            foreach($parameter as $title=>$value) {
                $expUpdate[] =  ' `'.$title.'`='.$value.' ';
            }
            $SQL = 'UPDATE `'.$this->tb.'` SET '.implode(',',$expUpdate)
                    .' WHERE `'.$this->pk.'` = ?';
            $parameterExec[] = $this->colsValues[$this->pk];
            $insert = false;
        }else {
            $sqlCols = implode('`,`',array_keys($parameter));
            $sqlPrep = implode(',',$parameter);
            $SQL = 'INSERT INTO '.$this->tb.'(`'.$sqlCols.'`)  VALUES('.$sqlPrep.') ';
            $insert = true;
        }
        $result  = Nucleo_Model_Model::exec($SQL,$parameterExec);
        $thisObj = $result->fetchObject();
        
        $this->findById($this->colsValues[$this->pk]);
        
        return $result;
    }

    /**
     * Maker of the SQL DELETE query
     * @return boolean
     */
    public function delete() {
        $retorno = TRUE;

        if(!isset(self::$instanceId[$this->tb][$this->colsValues[$this->pk]])) {
            $retorno = FALSE;
        }else {
            $SQL =  'DELETE FROM `'.$this->tb.'` WHERE `'.$this->pk.'`= ?';
            $result = Nucleo_Model_Model::exec($SQL,Array($this->colsValues[$this->pk]));

            if($result) {
                self::$instanceId[$this->tb][$this->pk] = NULL;
                $this->colsValues = Array();
            }
        }
        
        return $retorno;
    }

    /**
     * Find All objects in database
     * @param <type> $where
     * @param <type> $parameter
     * @return <type>
     */
    public function findAll($where = NULL,$parameter = NULL) {


        $SQL = 'SELECT '.implode(',',array_keys($this->cols)).' FROM `'.$this->tb.'` '.$where;


        $result = Nucleo_Model_Model::exec($SQL,$parameter);

        $__obj = null;
        $objsList = Array();
        if($result) {

            $constructParameter = Array(
                    'tb'=>$this->tb
                    ,'pk'=>$this->pk
                    ,'fk'=>$this->fk
                    ,'cols'=>$this->cols
                    ,'varUpper'=>$this->varUpper
            );

            while($obj = $result->fetch(PDO::FETCH_ASSOC)) {
                $__obj = self::createMapper($constructParameter,$obj[$this->pk]);
                foreach($obj as $title=>$value) {
                    if($this->varUpper)
                        $title = strtoupper($title);
                    if($title == $this->pk)
                        self::$instanceId[$this->tb][$value] = $__obj;

                    if(isset($this->fk[$title])) {
                        eval('$child = '.ucfirst(strtolower($this->fk[$title])).'::create();');
                        if($child->findById($value))
                            $__obj->addChildren($child,$this->fk[$title]);
                    }

                    $set = 'set'.$title;
                    $__obj->$set($value);
                }
                $objsList[] = $__obj;
            }

        }
        return $objsList;
    }

    /**
     * Maker of the SQL SELECT query
     * @param string $id
     * @return array Nucleo_Model_Object
     */
    public function findById($id) {
        $RETURN = FALSE;

        if(isset($id)) {
            $parameter[] = $id;
            $where = ' WHERE `'.$this->pk.'` = ? ';
        }else {
            throw new Nucleo_Exception_Sifra('031',true);
        }



        $SQL = 'SELECT '.implode(',',array_keys($this->cols)).' FROM `'.$this->tb.'` '.$where;


        $result = Nucleo_Model_Model::exec($SQL,$parameter);

        while($obj = $result->fetch(PDO::FETCH_ASSOC)) {
            $RETURN = TRUE;
            $constructParameter = Array(
                    'tb'=>$this->tb
                    ,'pk'=>$this->pk
                    ,'fk'=>$this->fk
                    ,'cols'=>$this->cols
                    ,'varUpper'=>$this->varUpper
            );

            $__obj = self::createMapper($constructParameter,$obj[$this->pk]);

            foreach($obj as $title=>$value) {
                if($this->varUpper)
                    $title = strtoupper($title);

                if(isset($this->fk[$title])) {
                    eval('$child = '.ucfirst(strtolower($this->fk[$title])).'::create();');
                    if($child->findById($value))
                        $this->addChildren($child,$this->fk[$title]);
                }

                $set = 'set'.$title;

                $__obj->$set($value);
                $this->$set($value);
            }

            self::$instanceId[$this->tb][$obj[$this->pk]] = $__obj;
        }

        return $RETURN;

    }

    /**
     * Return the cols of table
     */
    public function getObjectCols() {
        return array_keys($this->cols);
    }

    public function getPkName() {
        return $this->pk;
    }

    public function getChildrens() {
        return $this->children;
    }

    public function getFkTable($key){
        return $this->fk[$key];
    }

    public function getPkValue(){
        $getId = 'get'.$this->pk;
        return $this->$getId();
    }

    public function getTbName(){
        return $this->tb;
    }

    private function addChildren(Nucleo_Model_Object $obj,$tableName) {
        $this->children[$tableName] = $obj;
    }
    /**
     * Call of the sets e gets methods
     *
     * @param <type> $method
     * @param <type> $parameter
     * @return <type>
     */
    public function __call($method,$parameter) {
        $size = strlen($method);
        $varName = substr($method,3,$size);
        $method = substr($method,0,3);


        if($this->varUpper)
            $varName = strtoupper($varName);

        if ($method == 'set') {
            $type = $this->cols[$varName];
            // settype($parameter[0],$type);
            $this->colsValues[$varName] = $parameter[0];
        }
        elseif($method == 'get') {
            return $this->colsValues[$varName];

        }

    }




}

?>
